import os
import sys
import random
sys.path.insert(0, os.path.expanduser('~') + '/lib/python')

from mylib.gl3d.drawobject import *
from mylib.gl3d.light import *
from mylib.gl3d.camera import *
from mylib.gl3d.font import *
from mylib.gl3d.texture import *
from mylib.game.gamemap import *


SCREEN_SIZE = (800, 600)
mouse_drag = 0
mouse_last_pos = 0, 0


# The function called when our window is resized (which shouldn't happen if you enable fullscreen, below)
def glResize3D(width, height):
    # Prevent A Divide By Zero If The Window Is Too Small
    if height < 1: height = 1

    glViewport(0, 0, width, height)  # Reset The Current Viewport And Perspective Transformation
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()

    # // field of view, aspect ratio, near and far
    # This will squash and stretch our objects as the window is resized.
    gluPerspective(45.0, float(width) / float(height), 0.01, 500.0)

    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()


def glResize2D(width, height):
    # Prevent A Divide By Zero If The Window Is Too Small
    if height < 1: height = 1

    glViewport(0, 0, width, height)  # Reset The Current Viewport And Perspective Transformation
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()

    # // Establish clipping volume (left, right, bottom, top, near, far)
    # glOrtho(0, width, 0, height, 0.0, 5000.0)

    gluOrtho2D(0, 0 + width, 0, 0 + height)

    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()


def gen_points(n):
    vn = n * 3
    va = np.zeros(vn, 'f')
    i = 0
    while i < vn:
        v = random.randrange(0, 1000) / 100.0 - 5.0
        if -5.0 < v < 5.0:
            va[i] = v
            i += 1
        # points.append(Vec3d(random.randrange(0, 1000) / 100.0,
        #                     random.randrange(0, 1000) / 100.0,
        #                     random.randrange(0, 1000) / 100.0))
    return va, vn


def draw_points(va, vn, vertex_array=True):
        glDisable(GL_LIGHTING)
        i = 0
        while i < vn:
            v = random.randrange(0, 1000) / 100.0 - 5.0
            if -5.0 < v < 5.0:
                va[i] = v
                i += 1
        glColor3f(1.0, 1.0, 1.0)

        if vertex_array:
            glEnableClientState(GL_VERTEX_ARRAY)  # // Enable Vertex Arrays
            # // Set The Vertex Pointer To Our Vertex Data
            glVertexPointer(3, GL_FLOAT, 0, va)
            glDrawArrays(GL_POINTS, 0, vn // 3)  # // Draw All Of The Triangles At Once
            glDisableClientState(GL_VERTEX_ARRAY)  # // Disable Vertex Arrays
        else:
            # li = glGenLists(1)
            # glNewList(li, GL_COMPILE)
            # glBegin(GL_POINTS)
            # for i in range(vn // 3):
            #     glVertex3f(va[i * 3], va[i * 3 + 1], va[i * 3 + 2])
            # glEnd()
            # glEndList()
            # glCallList(li)
            # glDeleteLists(li, 1)
            pass


def draw_object(do):
        glColor3f(1.0, 0.0, 1.0)
        do.glDrawCube(0, 0, 0)
        glColor3f(1.0, 0.0, 0.0)
        do.gluDrawSphere(1, 0, 0, 0.5)
        glColor3f(0.0, 1.0, 0.0)
        do.gluDrawSphere(0, 1, 0, 0.5)
        glColor3f(0.0, 0.0, 1.0)
        do.gluDrawSphere(0, 0, 1, 0.5)
        """
        glColor4f(1.0, 1.0, 1.0, 1.0)
        do.glDrawPyramid(0, 0, 0, height=2)
        do.gluDrawSphere(0, 0, 0)
        do.gluDrawCylinder(2, 0, 0)
        do.gluDrawDisk(2, 0, 0, rotate_x=180.0)
        do.gluDrawPartialDisk(2, 0, 1, 0.2, angle=270)
        # do.glDrawColorTri(0, 0, 0, 1)
        # do._draw_pyramid(1, 1, 1)
        """

def check_camera_move(event, camera):
    global mouse_drag, mouse_last_pos
    if event.type == MOUSEMOTION:  # {
        if mouse_drag in (1, 3):  # {
            mx, my = event.pos
            lx, ly = mouse_last_pos
            dx, dy = (mx - lx), (my - ly)
            mouse_last_pos = mx, my
            if mouse_drag == 3: camera.change_view(dy / 10.0, dx / 10.0)
            elif mouse_drag == 1: camera.move(_x=dx / 10.0, _z=dy / 10.0)
            print_camera_info(camera)
        # }
    # }
    if event.type == MOUSEBUTTONDOWN:  # {
        if event.button in (1, 3):  # {
            mouse_last_pos = event.pos
            mouse_drag = event.button
        # }
        if event.button == 4: camera.distance *= 0.8
        if event.button == 5: camera.distance *= 1.2
        print_camera_info(camera)
    # }
    if event.type == MOUSEBUTTONUP:
        if event.button in (1, 3): mouse_drag = 0


def print_camera_info(cam):
    print('rotate = %5.2f, angle = %5.2f, distance = %8.3f, '
          'camera = (%5.2f,%5.2f,%5.2f), target = (%5.2f,%5.2f,%5.2f)' %
          (cam.rotate, cam.angle, cam.distance,
           cam.camera.x, cam.camera.y, cam.camera.z,
           cam.target.x, cam.target.y, cam.target.z))


def get_light_pos(cam):
    dist = cam.distance * 1.5
    p1 = cam.get_position(cam.target, distance=dist)
    # p1 = cam.camera

    d = Vec3d()
    d.x = -math.sin(math.radians(cam.rotate + 90))
    d.y = -math.tan(math.radians(cam.angle))
    d.z = math.cos(math.radians(cam.rotate + 90))
    return p1, d


def get_shader_src():
    return """
    vec3 ambient_light = light_ambient(light1).rgb+
                         light_ambient(light2).rgb+
                         light_ambient(light3).rgb+
                         light_ambient(light4).rgb+
                         light_ambient(light5).rgb+
                         light_ambient(light6).rgb+
                         light_ambient(light7).rgb+
                         light_ambient(light8).rgb;

    vec3 diffuse_light = light_diffuse(light1).rgb*light_att(light1)+
                     2.0*light_diffuse(light2).rgb*light_att(light2)*light_spot(light2)+
                         light_diffuse(light3).rgb*light_att(light3)+
                     2.0*light_diffuse(light4).rgb*light_att(light4)*light_spot(light4)+
                         light_diffuse(light5).rgb*light_att(light5)+
                     2.0*light_diffuse(light6).rgb*light_att(light6)*light_spot(light6)+
                         light_diffuse(light7).rgb*light_att(light7)+
                     2.0*light_diffuse(light8).rgb*light_att(light8)*light_spot(light8);

    vec3 specular_light = light_specular_ph(light1).rgb*light_att(light1)+
                      2.0*light_specular_ph(light2).rgb*light_att(light2)*light_spot(light2)+
                          light_specular_ph(light3).rgb*light_att(light3)+
                      2.0*light_specular_ph(light4).rgb*light_att(light4)*light_spot(light4)+
                          light_specular_ph(light5).rgb*light_att(light5)+
                      2.0*light_specular_ph(light6).rgb*light_att(light6)*light_spot(light6)+
                          light_specular_ph(light7).rgb*light_att(light7)+
                      2.0*light_specular_ph(light8).rgb*light_att(light8)*light_spot(light8);

    color.rgb += ambient_color.rgb*ambient_light;
    color.rgb += diffuse_color.rgb*diffuse_light;
    color.rgb += specular_color.rgb*specular_light;
    color.rgba *= texture2D(tex2D_1,uv).rgba; // texture color
    """


def DrawText(font, xx, yy, zz, tt):
        glColor3f(0.0, 1.0, 0.0)
        glMatrixMode(GL_PROJECTION)  # // Select The Projection Matrix
        glPushMatrix()  # // Store The Projection Matrix
        glLoadIdentity()  # // Reset The Projection Matrix
        glResize2D(SCREEN_SIZE[0], SCREEN_SIZE[1])
        glMatrixMode(GL_MODELVIEW)  # // Select The Modelview Matrix
        glPushMatrix()  # // Store The Modelview Matrix
        glLoadIdentity()  # // Reset The Modelview Matrix

        font.glPrint(xx, yy, zz, tt)

        glMatrixMode(GL_PROJECTION)  # // Select The Projection Matrix
        glPopMatrix()  # // Restore The Old Projection Matrix
        glMatrixMode(GL_MODELVIEW)  # // Select The Modelview Matrix
        glPopMatrix()  # // Restore The Old Projection Matrix
        # glResize3D(SCREEN_SIZE[0], SCREEN_SIZE[1])


def main():
    usr_home = os.path.expanduser('~')
    data_home = usr_home + '/src/res/'

    pygame.init()

    screen = pygame.display.set_mode(SCREEN_SIZE, HWSURFACE | OPENGL | DOUBLEBUF)

    glInit(blend=True, cull=True, clear=(0.2, 0.2, 0.2, 1.0))
    # glInitFog()
    glResize3D(SCREEN_SIZE[0], SCREEN_SIZE[1])

    bullet = []

    # --------------------------------------------------------- Font
    # our_font = font_data("arial.ttf", 16)
    font = glFont()
    # font.BuildFont(data_home + 'fonts/Gulim16.png', wchars=256, hchars=256, scale=1.0)
    font.BuildFont(data_home + 'fonts/font8x16.png', scale=1.0)

    # --------------------------------------------------------- Texture
    textures = Textures(lib=Textures.PIL)

    textures.load('tex', data_home + 'heightmap/texture.jpg')
    # textures.load('box', data_home + 'ammoc01.jpg')
    textures.load('box', data_home + 'crate2.jpg')

    # --------------------------------------------------------- Light
    light1 = Light3d(1)
    light1.set_type(MYGL_POINT_LIGHT)
    light1.set_diffuse([0.8, 0.8, 0.8])
    light1.enable()

    # --------------------------------------------------------- Shader
    shader = None
    '''
    shader = GLShader()
    shader.render_equation(get_shader_src())
    errors = shader.compile()
    print('Shader Load Check - ', errors)
    '''

    # --------------------------------------------------------- Camera
    camera = Camera(Camera.CT_CAMERA)
    camera.set_angle_limit(360)
    camera.distance = 25

    # --------------------------------------------------------- Game
    game_map = GameMap()
    game_map.set_texture(11, textures.get('box'))

    tet = TetrisItem()
    tet.set_type(random.randrange(7), 0)
    tet.set_pos(5, 0, 25)
    tet.set_dst(5, 0, 20)

    va, vn = gen_points(100)
    do = DrawObject()
    clock = pygame.time.Clock()

    while True:
        for event in pygame.event.get():
            if event.type == QUIT: return
            if event.type == KEYUP and event.key == K_ESCAPE: return
            check_camera_move(event, camera)
            if event.type == KEYDOWN and event.key == K_UP:
                tet.rotate(1)
                if not game_map.check_collide(tet.get_cell_positions()): tet.rotate(-1)
            if event.type == KEYDOWN and event.key == K_LEFT:
                tet.move(1, 0, 0)
                if not game_map.check_collide(tet.get_cell_positions()): tet.move(-1, 0, 0)
            if event.type == KEYDOWN and event.key == K_RIGHT:
                tet.move(-1, 0, 0)
                if not game_map.check_collide(tet.get_cell_positions()): tet.move(1, 0, 0)
            if event.type == KEYDOWN and event.key == K_DOWN:
                tet.move(0, 0, -1)
                if not game_map.check_collide(tet.get_cell_positions()): tet.move(0, 0, 1)
            if event.type == KEYDOWN and event.key == K_SPACE:
                tet.move(0, 0, -1)
                while game_map.check_collide(tet.get_cell_positions()): tet.move(0, 0, -1)
                tet.move(0, 0, 1)
        time_passed = clock.tick(29)
        time_passed_seconds = time_passed / 1000.

        game_map.update(time_passed_seconds)
        ret = tet.update(time_passed_seconds)
        if ret & GameItem.MOVE_END_Z == GameItem.MOVE_END_Z:
            tet.move(0, 0, -1)
            vl = tet.get_cell_positions()
            if not game_map.check_collide(vl):
                tet.set_dst(tet.dst.x, tet.dst.y, tet.dst.z + 1)
                game_map.set_tet(tet)
                game_map.check_match()
                tet = TetrisItem()
                tet.set_type(random.randrange(7), 0)
                tet.set_pos(5, 0, 25)
                tet.set_dst(5, 0, 20)

        # Clear the screen, and z-buffer
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        # Reset The Modelview Matrix
        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()
        glEnable(GL_LIGHTING)
        glEnable(GL_DEPTH_TEST)
        # glDisable(GL_BLEND)

        camera.look()
        p1, _ = get_light_pos(camera)
        light1.set_pos([p1.x, p1.y, p1.z])
        material_set(MYGL_MATERIAL_DEFAULT)
        textures.bind('tex')
        glColor4f(1.0, 1.0, 1.0, 1.0)
        do.glDrawQuad(5.5, -1.0, 11.0, ('xz', 15, 20))

        # ----------------------------------------------------------------------- Draw Game
        textures.bind('box')
        game_map.render(None)
        tet.render(None)

        # ----------------------------------------------------------------------- Draw Info
        glDisable(GL_TEXTURE_2D)

        # draw_points(va, vn)
        # draw_object(do)

        DrawText(font, 0, 0, 0, "ASDF asdf dfgdsf 3453456")
        glEnable(GL_LIGHTING)

        # Show the screen
        pygame.display.flip()

if __name__ == '__main__':
    main()